package m.system.util;

import m.system.exception.MException;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URL;
import java.nio.file.Files;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;




public class ClassUtil {
	public static void main(String[] a){ 
//		a=getAllQualifiedName4Class("m.base.model");
//		for(int i=0;i<a.length;i++){
//			SystemUtil.println(a[i]);
//		}
	}
	private static final String TYPE_NAME_PREFIX = "class ";

	public static String getClassName(Type type) {
		if (type==null) {
			return null;
		}
		String className = type.toString();
		if (className.startsWith(TYPE_NAME_PREFIX)) {
			className = className.substring(TYPE_NAME_PREFIX.length());
		}
		return className;
	}

	public static Class<?> getClass(String className) throws ClassNotFoundException {
		return Class.forName(className);
	}
	@SuppressWarnings("unchecked")
	public static <T> Class<? extends T> getClass(Class<T> clazz,String className) throws ClassNotFoundException {
		return (Class<T>)Class.forName(className);
	}
	public static Class<?> getClass(Type type) throws ClassNotFoundException {
		String className = getClassName(type);
		if (StringUtil.isSpace(className)) {
			return null;
		}
		return Class.forName(className);
	}
	public static Object newInstanceGenerics(Field field,int index) throws ClassNotFoundException, MException{
		Type mapMainType = field.getGenericType();   
		if (mapMainType instanceof ParameterizedType) {   
			ParameterizedType parameterizedType = (ParameterizedType)mapMainType;
			Type[] types = parameterizedType.getActualTypeArguments();
			return newInstance(getClass(types[index]));
		}
		return null;
	}
	/**
	 * 实例化对象
	 *  <T>
	 *  clazz
	 * 
	 *  MException
	 */
	public static <T> T newInstance(Class<T> clazz) throws MException{
		try {
			return clazz.getConstructor(new Class[]{}).newInstance();
		} catch (Exception e) {
			throw new MException(ClassUtil.class,"类实例化失败!"+e.getMessage());
		} 
	}
	@SuppressWarnings("unchecked")
	public static <T> T newInstance(String className) throws MException{
		try {
			Class<T> clazz=(Class<T>) Class.forName(className);
			return newInstance(clazz);
		} catch (Exception e) {
			throw new MException(ClassUtil.class,"类实例化失败!"+e.getMessage());
		} 
	}
	/**
	 * 获取属性字段, 没有的话找父类
	 */
	public static Field getDeclaredField(Class<?> clazz,String fieldName){
		do{
			try{
				return clazz.getDeclaredField(fieldName);
			}catch(Exception e){
				clazz=clazz.getSuperclass();
			}
		}while(clazz!=Object.class);
		return null;
	}
	/**
	 * 获取所有属性字段, 包括父类的
	 */
	public static Field[] getDeclaredFields(Class<?> clazz){
		List<Field> fields= new ArrayList<>();
		do{
			fields.addAll(0,Arrays.asList(clazz.getDeclaredFields()));
			clazz=clazz.getSuperclass();
		}while(clazz!=Object.class);
		return fields.toArray(new Field[]{});
	}

	/**
	 * 获取所有方法，包括父类的
	 */
	public static Method[] getDeclaredMethods(Class<?> clazz){
		List<Method> methods= new ArrayList<>();
		do{
			methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
			clazz=clazz.getSuperclass();
		}while(null!=clazz&&clazz!=Object.class);
		return methods.toArray(new Method[]{});
	}

	/**
	 * 获取方法，包括父类的
	 */
	public static Method getDeclaredMethods(Class<?> clazz,String method,Class<?>... params) {
		do{
			try {
				return clazz.getDeclaredMethod(method,params);
			} catch (NoSuchMethodException e) {
				clazz=clazz.getSuperclass();
			}
		}while(clazz!=Object.class);
		return null;
	}
	/**
	 * 
	 *  packeageName
	 * 
	 */
	public static List<String> getAllQualifiedName4Class(String packageName){
		String packagePath=packageName.replaceAll("\\.", "/");
		List<String> names= new ArrayList<>();
		try {
			URL url=Thread.currentThread().getContextClassLoader().getResource(packagePath);
			String path=url.getPath();
			int pos = path.indexOf('!');
			path=-1==pos?path:path.substring(5, pos);
			if(path.endsWith(".jar")) {
				JarInputStream jarIn = new JarInputStream(Files.newInputStream(new File(path).toPath()));
				JarEntry entry = jarIn.getNextJarEntry();
				while (null != entry) {
					String name = entry.getName();
					if (name.startsWith(packagePath) && name.endsWith(".class")) {
						names.add(name.substring(0, name.lastIndexOf(".")).replaceAll("/", "."));
					}
					entry = jarIn.getNextJarEntry();
				}
			}else {
				File file=new File(path);
				if(file.isDirectory()){
					List<String> packList=new ArrayList<>();
					for(String name : Objects.requireNonNull(file.list())){
						if(!name.contains(".")) {
							packList.add(name);
						}else {
							names.add(packageName+"."+name.substring(0, name.lastIndexOf(".")));
						}
					}
					for(String name : packList){
						names.addAll(getAllQualifiedName4Class(packageName+"."+name));
					}
				}
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
		return names;
//		File file=new File(Thread.currentThread().getContextClassLoader().getResource(packeageName.replaceAll("\\.", "/")).getPath());
//		if(file.isDirectory()){
//			String[] names=file.list();
//			for(int i=0;i<names.length;i++){
//				names[i]=packeageName+"."+names[i].substring(0, names[i].lastIndexOf("."));
//			}
//			return names;
//		}
//		return new String[]{};
	}
	/**
	 * 获取对象的get方法返回值
	 *  obj 
	 *  fieldName
	 * 
	 *  MException
	 */
	public static Object getFieldValue(Object obj,String fieldName) throws MException {
		String[] fns=fieldName.split("\\.");
		if(fns.length==1){
			if(obj instanceof Map) {
				return ((Map<?, ?>)obj).get(fieldName);
			}
			String stringLetter = fieldName.substring(0, 1).toUpperCase();
			String getName = "get" + stringLetter + fieldName.substring(1);
			Method getMethod;
			try {
				getMethod = obj.getClass().getMethod(getName);
				return getMethod.invoke(obj);
			} catch (Exception e) {
				//e.printStackTrace();
				throw new MException(ClassUtil.class,"获取get方法返回值失败!"+e.getMessage());
			}
		}else if(fns.length>1){
			Object object=getFieldValue(obj, fns[0]);
			if(null!=object){
				return getFieldValue(object, fieldName.substring(fieldName.indexOf(".")+1));
			}else{
				return null;
			}
		}else{
			throw new MException(ClassUtil.class,"获取get方法时,fieldName参数错误!");
		}
	}
	/**
	 * 填充对象set方法值
	 *  obj
	 *  fieldName
	 *  value
	 *  MException
	 */
	public static void setFieldValue(Object obj,String fieldName,Object value) throws MException{
		String stringLetter = fieldName.substring(0, 1).toUpperCase();
		String setName = "set" + stringLetter + fieldName.substring(1);
		try {
			Class<?> clazz= Objects.requireNonNull(getDeclaredField(obj.getClass(), fieldName)).getType();
			Method setMethod = obj.getClass().getMethod(setName, clazz);
			setMethod.invoke(obj, ObjectUtil.convert(clazz,value));
		} catch (Exception e) {
			//e.printStackTrace();
			throw new MException(ClassUtil.class,"填充"+setName+"方法失败!");
		}
	}
	/**
	 * 对象执行方法
	 *  obj
	 *  method_name
	 * 
	 *  MException
	 */
	public static Object executeMethod(Object obj,String method_name) throws Exception{
		return executeMethod(obj, method_name, null, null);
	}
	/**
	 * 对象执行方法
	 *  obj
	 *  method_name
	 *  paramTypes
	 *  paramValues
	 * 
	 *  Exception 
	 */
	public static Object executeMethod(Object obj,String method_name,Class<?>[] paramTypes,Object[] paramValues) throws Exception{
		Method setMethod = obj.getClass().getMethod(method_name,paramTypes);
		return setMethod.invoke(obj, paramValues);
	}
	/*
	 * 获取泛型类Class对象，不是泛型类则返回null
	 */
	public static Class<?> getActualTypeArgument(Class<?> clazz) {
		Class<?> entitiClass = null;
		Type genericSuperclass = clazz.getGenericSuperclass();
		if (genericSuperclass instanceof ParameterizedType) {
			Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass)
					.getActualTypeArguments();
			if (actualTypeArguments != null && actualTypeArguments.length > 0) {
				entitiClass = (Class<?>) actualTypeArguments[0];
			}
		}

		return entitiClass;
	}
//	public static <T> T fillInAttribute(Class<T> clazz,String fieldName,HttpServletRequest request) throws MException{
//		try {
//			T returnObject=(T)clazz.getConstructor(new Class[]{}).newInstance(new Object[]{});
//			if(returnObject instanceof String){
//				
//			}
//			
//			return returnObject;
//		} catch (Exception e) {
//			throw new MException(ClassUtil.class,"填充属性失败!"+e.getMessage());
//		} 
//	}
}
